package main

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
)

var db *sql.DB

type user struct {
	id   int
	age  int
	name string
}

func initDB() (err error) {
	dsn := "root:HYJ=wvs1996@tcp(127.0.0.1:3306)/db1"
	db, err = sql.Open("mysql", dsn)
	if err != nil {
		panic(err)
	}
	err = db.Ping() //连接数据库失败返回err，成功返回nil
	if err != nil {
		return
	}
	db.SetMaxOpenConns(1) //连接池中与数据库建立连接的最大数目，默认为0（无限制）
	//db.SetMaxIdleConns()  //连接池中的最大闲置连接数，最大不能超过"最大连接数"，超过就最大闲置连接为"最大连接数"
	return
}

func queryRows() {
	sqlStr := "select id,name,age from users_info where id=?"
	rows, err := db.Query(sqlStr, "2")
	if err != nil {
		fmt.Printf("查询失败：%v", err)
		return
	}
	defer rows.Close()

	for rows.Next() {
		var u user
		err := rows.Scan(&u.id, &u.name, &u.age)
		if err != nil {
			fmt.Printf("读取失败：%v", err)
			return
		}
		fmt.Printf("查询结果：%#v\n ", u)
	}
}

// 插入数据
func insertRow() {
	sqlStr := "insert into users_info(name, age) values (?,?)"
	ret, err := db.Exec(sqlStr, "jack2", 20)
	if err != nil {
		fmt.Printf("插入失败:%v\n", err)
		return
	}

	theID, err := ret.LastInsertId()   // 新插入数据的id
	lineNum, err := ret.RowsAffected() //新插入数据影响的行数
	if err != nil {
		fmt.Printf("插入失败:%v\n", err)
		return
	}
	fmt.Printf("插入成功, id是 %d ；受影响的行数是:%v\n", theID, lineNum)
}
func updateRow() {
	sqlStr := "update users_info set age=? where name=?"
	ret, err := db.Exec(sqlStr, 22, "tom")
	if err != nil {
		fmt.Printf("更新失败:%v\n", err)
		return
	}

	lineNum, err := ret.RowsAffected() //更新数据影响的行数
	if err != nil {
		fmt.Printf("更新失败:%v\n", err)
		return
	}
	fmt.Printf("更新成功, 受影响的行数是:%v\n", lineNum) //更新成功, 受影响的行数是:0

}
func deleteRow() {
	sqlStr := "delete from  users_info where id=?"
	ret, err := db.Exec(sqlStr, 1)
	if err != nil {
		fmt.Printf("删除失败:%v\n", err)
		return
	}

	lineNum, err := ret.RowsAffected() //删除数据影响的行数
	if err != nil {
		fmt.Printf("删除失败:%v\n", err)
		return
	}
	fmt.Printf("删除失败, 受影响的行数是:%v\n", lineNum) //删除失败, 受影响的行数是:1

}

//事务
func transaction() {
	tx, err := db.Begin()
	if err != nil {
		fmt.Printf("创建事务错误，%v\n", err)
		return
	}
	//第一条SQL语句
	res, err := tx.Exec("insert into users_info(name,age) values (?,?)", "hhh", 20)
	if err != nil {
		fmt.Printf("回滚事务，第一条SQL语句错误，%v\n", err)
		tx.Rollback()
		return
	}
	if firstRowNum, err := res.RowsAffected(); err != nil || firstRowNum != 1 {
		fmt.Printf("回滚事务，第一条SQL语句错误，%v\n", err)
		tx.Rollback()
		return
	}

	//第二条SQL语句
	res, err = tx.Exec("select * from users_info where id=?", 22)
	if err != nil {
		fmt.Printf("回滚事务，第二条SQL语句错误，%v\n", err)
		tx.Rollback()
		return
	}
	if secondRowNum, err := res.RowsAffected(); err != nil || secondRowNum != 1 {
		fmt.Printf("回滚事务,第二条SQL语句错误，%v\n", err)
		tx.Rollback()
		return
	}

	//
	fmt.Printf("提交事务")
	tx.Commit() // 提交事务

}
func main() {
	if err := initDB(); err != nil {
		fmt.Printf("err:%v", err)
	}

	defer db.Close() //必须确保db不为nil，才能调用Close
	transaction()
}
